package com.container.util;

import java.util.Collection;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;

public class TaskQueue extends LinkedBlockingQueue<Runnable> {

    private static final long serialVersionUID = 1L;
    private volatile ThreadPoolExecutor parent = null;
    private Integer forcedRemainingCapacity = null;

    public TaskQueue() {
        super();
    }

    public TaskQueue(int capacity) {
        super(capacity);
    }

    public TaskQueue(Collection<? extends Runnable> c) {
        super(c);
    }

    public void setParent(ThreadPoolExecutor executor) {
        parent = executor;
    }

    //当任务被ThreadPoolExecutor拒绝时，会尝试重新压入队列
    public boolean force(Runnable task) {
        if ( parent==null || parent.isShutdown() ) throw new RejectedExecutionException("Executor is not started, fail to force task into queue");
        return super.offer(task);
    }

    public boolean force(Runnable task, long timeout, TimeUnit unit) throws InterruptedException {
        if ( parent==null || parent.isShutdown() ) throw new RejectedExecutionException("Executor is not started, fail to force task into queue");
        return super.offer(task,timeout,unit);
    }

    @Override
    public boolean offer(Runnable task) {
        if (parent==null) return super.offer(task);
        if (parent.getPoolSize() == parent.getMaximumPoolSize()) return super.offer(task);//工作线程数达到上限，直接将任务加入队列
        if (parent.getSubmittedCount()<(parent.getPoolSize())) return super.offer(task);//有空闲线程时，将任务加入队列，
        if (parent.getPoolSize()<parent.getMaximumPoolSize()) return false;//线程数未达到上限且无空闲线程时，创建新线程
        return super.offer(task);
    }

    @Override
    public Runnable poll(long timeout, TimeUnit unit)
            throws InterruptedException {
        return super.poll(timeout, unit);//取任务
    }

    @Override
    public Runnable take() throws InterruptedException {
        return super.take();
    }

    @Override
    public int remainingCapacity() {
        if (forcedRemainingCapacity != null) {
            return forcedRemainingCapacity.intValue();
        }
        return super.remainingCapacity();
    }

    public void setForcedRemainingCapacity(Integer forcedRemainingCapacity) {
        this.forcedRemainingCapacity = forcedRemainingCapacity;
    }

}